static int svm_reset_to_realmode(
struct vcpu *v, struct cpu_user_regs *regs);
static void svm_update_guest_cr(struct vcpu *v, unsigned int cr);
+static void svm_update_guest_efer(struct vcpu *v);
+static void svm_inject_exception(
+ unsigned int trapnr, int errcode, unsigned long cr2);
/* va of hardware host save area */
static void *hsa[NR_CPUS] __read_mostly;
/* vmcb used for extended host state */
static void *root_vmcb[NR_CPUS] __read_mostly;
-static void svm_update_guest_efer(struct vcpu *v);
-
static void inline __update_guest_eip(
struct cpu_user_regs *regs, unsigned int inst_len)
{
+ struct vcpu *curr = current;
+
if ( unlikely((inst_len == 0) || (inst_len > 15)) )
{
gdprintk(XENLOG_ERR, "Bad instruction length %u\n", inst_len);
- domain_crash(current->domain);
+ domain_crash(curr->domain);
return;
}
regs->eip += inst_len;
regs->eflags &= ~X86_EFLAGS_RF;
- current->arch.hvm_svm.vmcb->interrupt_shadow = 0;
-}
-
-static void svm_inject_exception(
- struct vcpu *v, int trap, int ev, int error_code)
-{
- eventinj_t event;
- struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
-
- if ( trap == TRAP_page_fault )
- HVMTRACE_2D(PF_INJECT, v, v->arch.hvm_vcpu.guest_cr[2], error_code);
- else
- HVMTRACE_2D(INJ_EXC, v, trap, error_code);
-
- event.bytes = 0;
- event.fields.v = 1;
- event.fields.type = X86_EVENTTYPE_HW_EXCEPTION;
- event.fields.vector = trap;
- event.fields.ev = ev;
- event.fields.errorcode = error_code;
+ curr->arch.hvm_svm.vmcb->interrupt_shadow = 0;
- vmcb->eventinj = event;
+ if ( regs->eflags & X86_EFLAGS_TF )
+ svm_inject_exception(TRAP_debug, HVM_DELIVER_NO_ERROR_CODE, 0);
}
static void svm_cpu_down(void)
{
struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
- ASSERT(!v->arch.hvm_vcpu.flag_dr_dirty);
+ if ( v->arch.hvm_vcpu.flag_dr_dirty )
+ return;
+
v->arch.hvm_vcpu.flag_dr_dirty = 1;
vmcb->dr_intercepts = 0;
svm_destroy_vmcb(v);
}
-static void svm_hvm_inject_exception(
+static void svm_inject_exception(
unsigned int trapnr, int errcode, unsigned long cr2)
{
- struct vcpu *v = current;
+ struct vcpu *curr = current;
+ struct vmcb_struct *vmcb = curr->arch.hvm_svm.vmcb;
+ eventinj_t event;
+
+ event.bytes = 0;
+ event.fields.v = 1;
+ event.fields.type = X86_EVENTTYPE_HW_EXCEPTION;
+ event.fields.vector = trapnr;
+ event.fields.ev = (errcode != HVM_DELIVER_NO_ERROR_CODE);
+ event.fields.errorcode = errcode;
+
+ vmcb->eventinj = event;
+
if ( trapnr == TRAP_page_fault )
- v->arch.hvm_svm.vmcb->cr2 = v->arch.hvm_vcpu.guest_cr[2] = cr2;
- svm_inject_exception(v, trapnr, (errcode != -1), errcode);
+ {
+ vmcb->cr2 = curr->arch.hvm_vcpu.guest_cr[2] = cr2;
+ HVMTRACE_2D(PF_INJECT, curr, curr->arch.hvm_vcpu.guest_cr[2], errcode);
+ }
+ else
+ {
+ HVMTRACE_2D(INJ_EXC, curr, trapnr, errcode);
+ }
+
+ if ( (trapnr == TRAP_debug) &&
+ (guest_cpu_user_regs()->eflags & X86_EFLAGS_TF) )
+ {
+ __restore_debug_registers(curr);
+ vmcb->dr6 |= 0x4000;
+ }
}
static int svm_event_pending(struct vcpu *v)
.update_vtpr = svm_update_vtpr,
.stts = svm_stts,
.set_tsc_offset = svm_set_tsc_offset,
- .inject_exception = svm_hvm_inject_exception,
+ .inject_exception = svm_inject_exception,
.init_ap_context = svm_init_ap_context,
.init_hypercall_page = svm_init_hypercall_page,
.event_pending = svm_event_pending
if (!seg) /* If no prefix, used DS. */
seg = &vmcb->ds;
if (!long_mode && (seg->attr.fields.type & 0xa) == 0x8) {
- svm_inject_exception(v, TRAP_gp_fault, 1, 0);
+ svm_inject_exception(TRAP_gp_fault, 0, 0);
return 0;
}
}
reg = regs->edi;
seg = &vmcb->es; /* Note: This is ALWAYS ES. */
if (!long_mode && (seg->attr.fields.type & 0xa) != 0x2) {
- svm_inject_exception(v, TRAP_gp_fault, 1, 0);
+ svm_inject_exception(TRAP_gp_fault, 0, 0);
return 0;
}
}
/* If the segment isn't present, give GP fault! */
if (!long_mode && !seg->attr.fields.p)
{
- svm_inject_exception(v, TRAP_gp_fault, 1, 0);
+ svm_inject_exception(TRAP_gp_fault, 0, 0);
return 0;
}
*addr + size - 1 > seg->limit :
*addr <= seg->limit)
{
- svm_inject_exception(v, TRAP_gp_fault, 1, 0);
+ svm_inject_exception(TRAP_gp_fault, 0, 0);
return 0;
}
if (!is_canonical_address(*addr) ||
!is_canonical_address(*addr + size - 1))
{
- svm_inject_exception(v, TRAP_gp_fault, 1, 0);
+ svm_inject_exception(TRAP_gp_fault, 0, 0);
return 0;
}
if (*count > (1UL << 48) / size)
{
/* The guest does not have the RAM address mapped.
* Need to send in a page fault */
- svm_hvm_inject_exception(TRAP_page_fault, pfec, addr);
+ svm_inject_exception(TRAP_page_fault, pfec, addr);
return;
}
paddr = (paddr_t)gfn << PAGE_SHIFT | (addr & ~PAGE_MASK);
addr += size - rv;
gdprintk(XENLOG_DEBUG, "Pagefault reading non-io side "
"of a page-spanning PIO: va=%#lx\n", addr);
- svm_hvm_inject_exception(TRAP_page_fault, 0, addr);
+ svm_inject_exception(TRAP_page_fault, 0, addr);
return;
}
}
break;
case MSR_K8_VM_HSAVE_PA:
- svm_inject_exception(v, TRAP_gp_fault, 1, 0);
+ svm_inject_exception(TRAP_gp_fault, 0, 0);
break;
case MSR_IA32_MCG_CAP:
regs->edx = edx;
goto done;
}
- svm_inject_exception(v, TRAP_gp_fault, 1, 0);
+ svm_inject_exception(TRAP_gp_fault, 0, 0);
return;
}
regs->eax = msr_content & 0xFFFFFFFF;
break;
case MSR_K8_VM_HSAVE_PA:
- svm_inject_exception(v, TRAP_gp_fault, 1, 0);
+ svm_inject_exception(TRAP_gp_fault, 0, 0);
break;
case MSR_IA32_DEBUGCTLMSR:
inst_len = __get_instruction_length(curr, INSTR_HLT, NULL);
__update_guest_eip(regs, inst_len);
- /* Check for interrupt not handled or new interrupt. */
+ /* Check for pending exception or new interrupt. */
if ( vmcb->eventinj.fields.v ||
((intack.source != hvm_intsrc_none) &&
!svm_interrupt_blocked(current, intack)) )
break;
}
- v->arch.hvm_vcpu.guest_cr[2] = vmcb->cr2 = va;
- svm_inject_exception(v, TRAP_page_fault, 1, regs->error_code);
+ svm_inject_exception(TRAP_page_fault, regs->error_code, va);
break;
}
case VMEXIT_STGI:
case VMEXIT_CLGI:
case VMEXIT_SKINIT:
- svm_inject_exception(v, TRAP_invalid_op, 0, 0);
+ svm_inject_exception(TRAP_invalid_op, HVM_DELIVER_NO_ERROR_CODE, 0);
break;
case VMEXIT_NPF:
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307 USA.
- *
*/
#include <xen/config.h>
static void __restore_debug_registers(struct vcpu *v)
{
- ASSERT(!v->arch.hvm_vcpu.flag_dr_dirty);
+ if ( v->arch.hvm_vcpu.flag_dr_dirty )
+ return;
+
v->arch.hvm_vcpu.flag_dr_dirty = 1;
write_debugreg(0, v->arch.guest_context.debugreg[0]);
static void vmx_inject_exception(
unsigned int trapnr, int errcode, unsigned long cr2)
{
- struct vcpu *v = current;
- vmx_inject_hw_exception(v, trapnr, errcode);
+ struct vcpu *curr = current;
+
+ vmx_inject_hw_exception(curr, trapnr, errcode);
+
if ( trapnr == TRAP_page_fault )
- v->arch.hvm_vcpu.guest_cr[2] = cr2;
+ curr->arch.hvm_vcpu.guest_cr[2] = cr2;
+
+ if ( (trapnr == TRAP_debug) &&
+ (guest_cpu_user_regs()->eflags & X86_EFLAGS_TF) )
+ {
+ __restore_debug_registers(curr);
+ write_debugreg(6, read_debugreg(6) | 0x4000);
+ }
}
static void vmx_update_vtpr(struct vcpu *v, unsigned long value)
x &= ~(VMX_INTR_SHADOW_STI | VMX_INTR_SHADOW_MOV_SS);
__vmwrite(GUEST_INTERRUPTIBILITY_INFO, x);
}
+
+ if ( regs->eflags & X86_EFLAGS_TF )
+ vmx_inject_exception(TRAP_debug, HVM_DELIVER_NO_ERROR_CODE, 0);
}
static void vmx_do_no_device_fault(void)
static void vmx_do_hlt(struct cpu_user_regs *regs)
{
- HVMTRACE_0D(HLT, current);
+ unsigned long intr_info = __vmread(VM_ENTRY_INTR_INFO);
+ struct vcpu *curr = current;
+
+ /* Check for pending exception. */
+ if ( intr_info & INTR_INFO_VALID_MASK )
+ {
+ HVMTRACE_1D(HLT, curr, /*int pending=*/ 1);
+ return;
+ }
+
+ HVMTRACE_1D(HLT, curr, /*int pending=*/ 0);
hvm_hlt(regs->eflags);
}
case EXIT_REASON_VMWRITE:
case EXIT_REASON_VMXOFF:
case EXIT_REASON_VMXON:
- vmx_inject_hw_exception(v, TRAP_invalid_op, VMX_DELIVER_NO_ERROR_CODE);
+ vmx_inject_hw_exception(v, TRAP_invalid_op, HVM_DELIVER_NO_ERROR_CODE);
break;
case EXIT_REASON_TPR_BELOW_THRESHOLD: